/**
 * Beijing Jiaotong University
 * Copyright (c) 1896-2016 All Rights Reserved.
 */
package com.fesc.trade.demo.request;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fesc.trade.demo.model.BaseModel;
import com.fesc.trade.demo.model.ExtendParams;
import com.fesc.trade.demo.model.GoodsDetail;
import com.fesc.trade.demo.util.AssertUtil;

/**
 * 条码支付请求
 * @author HuHui
 * @version $Id: PayRequest.java, v 0.1 2016年8月18日 上午10:48:08 HuHui Exp $
 */
public class PayRequest extends BaseRequest {

    /** uid */
    private static final long   serialVersionUID = -6356051295938975445L;

    private BizContent          bizContent       = new BizContent();

    private Map<String, String> paraMap          = new TreeMap<String, String>();

    @Override
    public void validate() {

        super.validate();

        AssertUtil.assertNotBlank(bizContent.scene, "scene should not be NULL!");

        AssertUtil.assertNotBlank(bizContent.authCode, "auth_code should not be NULL!");

        if (!Pattern.matches("^\\d{10,}$", bizContent.authCode)) {
            throw new IllegalStateException("invalid auth_code!");
        }

        AssertUtil.assertNotBlank(bizContent.outTradeNo, "out_trade_no should not be NULL!");

        AssertUtil.assertNotBlank(bizContent.totalAmount, "total_amount should not be NULL!");

        AssertUtil.assertNotBlank(bizContent.subject, "subject should not be NULL!");

        AssertUtil.assertNotBlank(bizContent.merchantId, "merchantId should not be NULL!");

    }

    public String getMerchantId() {
        return bizContent.merchantId;
    }

    public PayRequest setMerchantId(String merchantId) {
        bizContent.merchantId = merchantId;
        return this;
    }

    public String getScene() {
        return bizContent.scene;
    }

    public PayRequest setScene(String scene) {
        bizContent.scene = scene;
        return this;
    }

    public String getAuthCode() {
        return bizContent.authCode;
    }

    public PayRequest setAuthCode(String authCode) {
        bizContent.authCode = authCode;
        return this;
    }

    public String getOutTradeNo() {
        return bizContent.outTradeNo;
    }

    public PayRequest setOutTradeNo(String outTradeNo) {
        bizContent.outTradeNo = outTradeNo;
        return this;
    }

    public String getSellerId() {
        return bizContent.sellerId;
    }

    public PayRequest setSellerId(String sellerId) {
        bizContent.sellerId = sellerId;
        return this;
    }

    public String getTotalAmount() {
        return bizContent.totalAmount;
    }

    public PayRequest setTotalAmount(String totalAmount) {
        bizContent.totalAmount = totalAmount;
        return this;
    }

    public String getDiscountableAmount() {
        return bizContent.discountableAmount;
    }

    public PayRequest setDiscountableAmount(String discountableAmount) {
        bizContent.discountableAmount = discountableAmount;
        return this;
    }

    public String getUndiscountableAmount() {
        return bizContent.undiscountableAmount;
    }

    public PayRequest setUndiscountableAmount(String undiscountableAmount) {
        bizContent.undiscountableAmount = undiscountableAmount;
        return this;
    }

    public String getSubject() {
        return bizContent.subject;
    }

    public PayRequest setSubject(String subject) {
        bizContent.subject = subject;
        return this;
    }

    public String getBody() {
        return bizContent.body;
    }

    public PayRequest setBody(String body) {
        bizContent.body = body;
        return this;
    }

    public List<GoodsDetail> getGoodsDetailList() {
        return bizContent.goodsDetailList;
    }

    public PayRequest setGoodsDetailList(List<GoodsDetail> goodsDetailList) {
        bizContent.goodsDetailList = goodsDetailList;
        return this;
    }

    public String getOperatorId() {
        return bizContent.operatorId;
    }

    public PayRequest setOperatorId(String operatorId) {
        bizContent.operatorId = operatorId;
        return this;
    }

    public String getStoreId() {
        return bizContent.storeId;
    }

    public PayRequest setStoreId(String storeId) {
        bizContent.storeId = storeId;
        return this;
    }

    public String getAlipayStoreId() {
        return bizContent.alipayStoreId;
    }

    public PayRequest setAlipayStoreId(String alipayStoreId) {
        bizContent.alipayStoreId = alipayStoreId;
        return this;
    }

    public String getTerminalId() {
        return bizContent.terminalId;
    }

    public PayRequest setTerminalId(String terminalId) {
        bizContent.terminalId = terminalId;
        return this;
    }

    public ExtendParams getExtendParams() {
        return bizContent.extendParams;
    }

    public PayRequest setExtendParams(ExtendParams extendParams) {
        bizContent.extendParams = extendParams;
        return this;
    }

    public String getTimeoutExpress() {
        return bizContent.timeoutExpress;
    }

    public PayRequest setTimeoutExpress(String timeoutExpress) {
        bizContent.timeoutExpress = timeoutExpress;
        return this;
    }

    public Map<String, String> buildParaMap() {
        super.setBizContent(bizContent.buildBizContentStr());

        if (StringUtils.isNotBlank(acquirerId)) {
            paraMap.put("acquirer_id", acquirerId);
        }
        if (StringUtils.isNotBlank(signType)) {
            paraMap.put("sign_type", signType);
        }
        if (StringUtils.isNotBlank(timestamp)) {
            paraMap.put("timestamp", timestamp);
        }
        if (StringUtils.isNotBlank(appAuthToken)) {
            paraMap.put("app_auth_token", appAuthToken);
        }
        if (StringUtils.isNotBlank(walletType)) {
            paraMap.put("wallet_type", walletType);
        }
        if (StringUtils.isNotBlank(super.bizContent)) {
            paraMap.put("biz_content", super.bizContent);
        }

        return paraMap;

    }

    /** 业务参数 */
    private static class BizContent extends BaseModel {

        /**  */
        private static final long serialVersionUID = 5574479268178892797L;

        // 商户标识号
        @JSONField(name = "merchant_id")
        private String            merchantId;

        // 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        @JSONField(name = "out_trade_no")
        private String            outTradeNo;

        // 支付场景，条码支付场景为bar_code
        private String            scene;

        // 付款条码，用户支付宝钱包手机app点击“付款”产生的付款条码
        @JSONField(name = "auth_code")
        private String            authCode;

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        @JSONField(name = "seller_id")
        private String            sellerId;

        // 订单总金额，整形，此处单位为元，精确到小数点后2位，不能超过1亿元
        // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
        @JSONField(name = "total_amount")
        private String            totalAmount;

        // 订单可打折金额，此处单位为元，精确到小数点后2位
        // 可以配合商家平台配置折扣活动，如果订单部分商品参与打折，可以将部分商品总价填写至此字段，默认全部商品可打折
        // 如果该值未传入,但传入了【订单总金额】,【不可打折金额】 则该值默认为【订单总金额】- 【不可打折金额】
        @JSONField(name = "discountable_amount")
        private String            discountableAmount;

        // 订单不可打折金额，此处单位为元，精确到小数点后2位，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        @JSONField(name = "undiscountable_amount")
        private String            undiscountableAmount;

        // 订单标题，粗略描述用户的支付目的。如“喜士多（浦东店）消费”
        private String            subject;

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        private String            body;

        // 商品明细列表，需填写购买商品详细信息，
        @JSONField(name = "goods_detail")
        private List<GoodsDetail> goodsDetailList;

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        @JSONField(name = "operator_id")
        private String            operatorId;

        // 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        @JSONField(name = "store_id")
        private String            storeId;

        // 支付宝商家平台中配置的商户门店号，详询支付宝技术支持
        @JSONField(name = "alipay_store_id")
        private String            alipayStoreId;

        // 商户机具终端编号，当以机具方式接入支付宝时必传，详询支付宝技术支持
        @JSONField(name = "terminal_id")
        private String            terminalId;

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        @JSONField(name = "extend_params")
        private ExtendParams      extendParams;

        // (推荐使用，相对时间) 支付超时时间，5m 5分钟
        @JSONField(name = "timeout_express")
        private String            timeoutExpress;

        public String buildBizContentStr() {

            Map<String, Object> bizParaMap = new TreeMap<String, Object>();

            if (StringUtils.isNotBlank(merchantId)) {
                bizParaMap.put("merchant_id", merchantId);
            }
            if (StringUtils.isNotBlank(outTradeNo)) {
                bizParaMap.put("out_trade_no", outTradeNo);
            }
            if (StringUtils.isNotBlank(scene)) {
                bizParaMap.put("scene", scene);
            }
            if (StringUtils.isNotBlank(authCode)) {
                bizParaMap.put("auth_code", authCode);
            }
            if (StringUtils.isNotBlank(sellerId)) {
                bizParaMap.put("seller_id", sellerId);
            }
            if (StringUtils.isNotBlank(totalAmount)) {
                bizParaMap.put("total_amount", totalAmount);
            }
            if (StringUtils.isNotBlank(discountableAmount)) {
                bizParaMap.put("discountable_amount", discountableAmount);
            }
            if (StringUtils.isNotBlank(undiscountableAmount)) {
                bizParaMap.put("undiscountable_amount", undiscountableAmount);
            }
            if (StringUtils.isNotBlank(subject)) {
                bizParaMap.put("subject", subject);
            }
            if (StringUtils.isNotBlank(body)) {
                bizParaMap.put("body", body);
            }
            if (CollectionUtils.isNotEmpty(goodsDetailList)) {
                bizParaMap.put("goods_detail", goodsDetailList);
            }
            if (StringUtils.isNotBlank(operatorId)) {
                bizParaMap.put("operator_id", operatorId);
            }
            if (StringUtils.isNotBlank(storeId)) {
                bizParaMap.put("store_id", storeId);
            }
            if (StringUtils.isNotBlank(alipayStoreId)) {
                bizParaMap.put("alipay_store_id", alipayStoreId);
            }
            if (StringUtils.isNotBlank(terminalId)) {
                bizParaMap.put("terminal_id", terminalId);
            }
            if (extendParams != null) {
                bizParaMap.put("extend_params", extendParams);
            }
            if (StringUtils.isNotBlank(timeoutExpress)) {
                bizParaMap.put("timeout_express", timeoutExpress);
            }

            return JSON.toJSONString(bizParaMap);
        }
    }

}
